iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 21
0
Software Development

從Java進入AWS部署RESTful API的心路歷程系列 第 21

Day21-實作(六)對DynamoDB進行CRUD

  • 分享至 

  • xImage
  •  

這次我們試用直接透過SDK的Dynamo Client進行項目操作。

起手式

針對Table的操作都很簡單,我們需要建立DynamoDB Client供DynamoDB Table使用。

AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
            .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("http://localhost:8000", "us-west-2"))
            .build();
DynamoDB dynamoDB = new DynamoDB(client);
Table table = dynamoDB.getTable("table1");

因為打算要連線的是DynamoDB-Local,所以要指定EndpointConfitguration,那如果要使用AWS雲端服務呢,就不需要指定了。

AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();

在不指定的情況下,Lambda連線的資料庫就是開發環境下AWS CLI設定的regions,在AWS雲端上執行的Lambda,就是使用與Lambda相同regions的DynamoDB

但是如果你實際連線DynamoDB-Local時發生socket refuse connection ,代表你跟我遇到一樣的問題。,那麼EndpointConfiguration請改用你環境local ip address或是使用alias ip address導向本機 。例如我的環境VirtualBox&Ubuntu,Ubuntu當中以ip address show查詢其中網卡enp0s3使用的位置是10.0.2.15。那麼EndpointConfiguration設定為http://10.0.2.15:8000 即可。

Create Item

首先我希望使用PUT /person來處理建立項目的方法,在template.yaml當中補上之前沒有的內容於UpdatePerson Events當中

        CreatePerson:
          Type: Api
          Properties:
            Path: /person
            Method: PUT

原本的updatePerson method當中path variable person_id判斷無值時回傳http500的邏輯拿掉,然後在if判斷httpMethod為PUT之中增加若無person_id則產生一個

if (StringUtils.isNullOrEmpty(person_id))
    person_id = UUID.randomUUID().toString();

接下來就是前面起手式那段取得DynamoDB Table後,進行putItem的操作

PutItemOutcome outcome = table.putItem(new Item().withPrimaryKey("pk_id", person_id)
    .withString("firstName", person.getFirstName())
    .withString("lastName", person.getLastName()) );
context.getLogger().log("PutItemOutcome:" + outcome.getPutItemResult().toString() + "\n");
person.setId(person_id);
return new ResponseBean(pseron, Views.idOnly.class);

(因為每個想要填值的屬性,操作時都要一個個塞值,所以這邊偷懶只處理pk_id與兩個屬性)
最後使用JsonView的技巧僅回傳新項目的id內容。

透過PostMan進行簡單測試,使用PUT /person並給予如下JSON

{"firstName": "Spencer", "lastName": "Liu", "email": "spencer@somwhere.com"}

不過當然,實際上只有firstName、lastName會存入資料庫。

成功時即取得新增項目的id

{
    "id": "069ee1b0-2a2b-4d7b-80e3-1367d16323fd"
}

Read Item

這邊用Get /person/{person_id} 來實作getItem。在queryPerson當中person_id判斷有值的段落增加起手式取得table及以下code

Item outcome = table.getItem(new GetItemSpec().withPrimaryKey("pk_id", person_id));
context.getLogger().log("item:" + outcome.toJSONPretty() + "\n");
Person person = new Person();
person.setId(outcome.getString("pk_id"));
person.setFirstName(outcome.getString("firstName"));
person.setLastName(outcome.getString("lastName"));
return new ResponseBean(person, View.Public.class);

這樣當我們使用get /person/069ee1b0-2a2b-4d7b-80e3-1367d16323fd

在log當中我們會看到

item:{
  "firstName" : "Spencer",
  "lastName" : "Liu",
  "pk_id" : "069ee1b0-2a2b-4d7b-80e3-1367d16323fd"
}

在response當中會看到

{
    "id": "069ee1b0-2a2b-4d7b-80e3-1367d16323fd",
    "firstName": "Spencer",
    "lastName": "Liu",
    "email": null,
    "phone": null,
    "gender": null
}

喔 等等,或許也可以改寫Jackson參數讓null不顯示出來,在ResponseBean.getBody中使用ObjectMapper之前設定

mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

這樣response會變成

{
    "id": "069ee1b0-2a2b-4d7b-80e3-1367d16323fd",
    "firstName": "Spencer",
    "lastName": "Liu"
}

Update Item

UpdateItem與PutItem就很類似了,我們在updatePerson當中處理POST /person/{person_id}的部分增加以下內容

if (StringUtils.isNullOrEmpty(person_id))
    return new ResponseBean(500);
/*
這邊填入起手式取得Table的部分
*/
String setStr = "";
ValueMap valueMap = new ValueMap();
if (!StringUtils.isNullOrEmpty(person.getFirstName())) {
    setStr = "firstName = :firstName";
    valueMap.withString(":firstName", person.getFirstName());
}
if (!StringUtils.isNullOrEmpty(person.getLastName())) {
    if (StringUtils.isNullOrEmpty(setStr))
        setStr = "lastName = :lastName";
    else setStr = setStr + ", lastName = :lastName";
    valueMap.withString(":lastName", person.getLastName());
}
if (StringUtils.isNullOrEmpty(setStr))
    return new ResponseBean(500);
UpdateItemSpec spec = new UpdateItemSpec().withPrimaryKey("pk_id", person_id)
    .withUpdateExpression("set " + setStr)
    .withValueMap(valueMap)
    .withReturnValues(ReturnValue.ALL_NEW);
UpdateItemOutcome outcome = table.updateItem(spec);
context.getLogger().log("PutItemOutcome:" + outcome.getUpdateItemResult().toString() + "\n");
person.setId(outcome.getItem().getString("pk_id"));
person.setFirstName(outcome.getItem().getString("firstName"));
person.setLastName(outcome.getItem().getString("lastName"));
return new ResponseBean(person, Views.Public.class);

我們測試用POST /person/069ee1b0-2a2b-4d7b-80e3-1367d16323fd
並且JSON內容使用

{"firstName": "Jack"}

更新完成後會得到完整的response,這是因為使用了ReturnValue.ALL_NEW

{
    "id": "069ee1b0-2a2b-4d7b-80e3-1367d16323fd",
    "firstName": "Jack",
    "lastName": "Liu"
}

Delete Item

刪除項目相對來說就簡單多了,在處理DELETE /person/{person_id}的deletePerson當中增加起手式及以下內容

table.deleteItem(new DeleteItemSpec().withPrimaryKey(new PrimaryKey("pk_id", person_id)));
return new ResponseBean(200);

試試執行刪除,然後再嘗試取得Item就找不到資料了

後記

經過初步的嘗試,會發現這樣操作存取項目會需要一個個處理所有屬性,相對來說每次不同的作業都要重複處理大量的程式碼。不過接下來我們會嘗試AWS SDK提供的物件持久性模型,會更容易將定義好的bean對應dynamodb項目操作。

而上述程式碼僅為了簡易測試,對於邏輯判斷及省略了錯誤處理,如果要正式實作記得要再加上喔。


上一篇
Day20-概論(十)DynamoDB程式設計介面
下一篇
Day22-概論(十一)DynamoDBMapper Class
系列文
從Java進入AWS部署RESTful API的心路歷程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言